﻿/**
 * @file		dd_pmc_i2c.h
 * @brief		I2C driver
 * @note		None
 * @attention	None
 * 
 * <B><I>Copyright 2016 Socionext Inc.</I></B>
 */

/** @weakgroup dd_pmc_i2c_overview
@{
	CM0 PMC - I2C Driver.<br>
	<br>
	The number of channels is 1 (ch0).
@}*//* --- end of dd_pmc_i2c_overview */

/** @weakgroup dd_pmc_i2c_sequence
@{
	- @ref dd_pmc_i2c_master_sequence_sect
	- @ref dd_pmc_i2c_slave_sequence_sect
	- @ref I2C_Sample_Master_Transmit
	- @ref I2C_Sample_Master_Receive
	- @ref I2C_Sample_Slave_Operation
	@section dd_pmc_i2c_master_sequence_sect		Sequence example of I2C (Master).
	@image html dd_pmc_i2c_master.png
	@section dd_pmc_i2c_slave_sequence_sect			Sequence example of I2C (Slave).
	@image html dd_pmc_i2c_slave.png
	@section I2C_Sample_Master_Transmit		I2C Sample Code for Master Transmit
	<table  border="1">
	<tr>
	  <th width="15.75">S</th>
	  <th width="74.25">Slave Address</th>
	  <th width="15.75">W</th>
	  <th width="22.5">Ack</th>
	  <th width="28.5">Data</th>
	  <th width="23.25">Ack</th>
	  <th width="20.25">...</th>
	  <th width="26.25">Data</th>
	  <th width="24.75">Ack</th>
	  <th width="18.75">P</th>
	</tr>
	</table>
	@code
	// Master Send Data to Slave
	VOID master_send_data_to_slave( VOID )
	{
		INT32 ret;
		T_DD_PMC_I2C_CTRL_MASTER ctrl_master;
		T_DD_PMC_I2C_START_INFO start_info;
		VP_PMC_I2C_CALLBACK callback = pmc_i2c_callback_func;
		UCHAR SendData[10] = { 0,1,2,3,4,5,6,7,8,9 };

		while(1){ // Retry loop as error occur

			ctrl_master.bps = E_DD_PMC_I2C_BPS_400;
			ctrl_master.dest_slave_addr_len = E_DD_PMC_I2C_ADDR_LEN_7;
			ctrl_master.dest_slave_addr = 0x45;

			ret = Dd_PMC_I2C_Ctrl_Master( &ctrl_master ); // Set Control for Master Operation
			if( ret == D_DDIM_OK ){

				start_info.rw_mode = E_DD_PMC_I2C_RW_MODE_WRITE;
				start_info.rw_data_len = sizeof(SendData);
				start_info.rw_data = SendData;

				ret = Dd_PMC_I2C_Start_Master( &start_info, callback ); // Start Send
				if( ret == D_DDIM_OK ){
					// Send OK
					Dd_PMC_I2C_Stop_Master(); // Stop Send
					break;
				}
			}
		}
	}
	@endcode
	<br>
	<br>

	@section I2C_Sample_Master_Receive		I2C Sample Code for Master Receive
	<table  border="1">
	<tr>
	  <th width="17.25">S</th>
	  <th width="75.75">Slave Address</th>
	  <th width="12.75">R</th>
	  <th width="20.25">Ack</th>
	  <th width="28.5">Data</th>
	  <th width="23.25">Ack</th>
	  <th width="20.25">...</th>
	  <th width="26.25">Data</th>
	  <th width="30.75">NoAck</th>
	  <th width="18.75">P</th>
	</tr>
	</table>
	@code
	// Master Receive Data from Slave
	VOID master_receive_data_from_slave(USHORT SlaveAddress)
	{
		INT32 ret;
		T_DD_PMC_I2C_CTRL_MASTER ctrl_master;
		T_DD_PMC_I2C_START_INFO start_info;
		VP_PMC_I2C_CALLBACK callback = pmc_i2c_callback_func;
		UCHAR RecvData[10];

		while(1){ // Retry loop as error occur

			ctrl_master.bps = E_DD_PMC_I2C_BPS_400;
			ctrl_master.dest_slave_addr_len = E_DD_PMC_I2C_ADDR_LEN_7;
			ctrl_master.dest_slave_addr = 0x45;

			ret = Dd_PMC_I2C_Ctrl_Master( &ctrl_master ); // Set Control for Master Operation
			if( ret == D_DDIM_OK ){

				start_info.rw_mode = E_DD_PMC_I2C_RW_MODE_READ;
				start_info.rw_data_len = sizeof(RecvData);
				start_info.rw_data = RecvData;

				ret = Dd_PMC_I2C_Start_Master( &start_info, callback ); // Start Receive
				if( ret == D_DDIM_OK ){
					// Receive OK
					Dd_PMC_I2C_Stop_Master(); // Stop Receive
					break;
				}
			}
		}
	}
	@endcode
	<br>
	<br>

	@section I2C_Sample_Slave_Operation		I2C Sample Code for Slave Operation
	@code
	// I2C Callback Function
	T_DD_PMC_I2C_ACTION pmc_i2c_callback_func( E_DD_PMC_I2C_RECV_FROM_MASTER receive_sig, UCHAR data )
	{
		T_DD_PMC_I2C_ACTION ret_act = { D_DD_PMC_I2C_SEND_NO_ACK_MASTER, 0 };

		switch( receive_sig ){
			case E_DD_PMC_I2C_RECV_FROM_MASTER_ADDRESS:
				// receive slave address
				gI2c_slave_send_address = 0x7000A000;
				gI2c_slave_recv_address = 0x7000B000;
				gI2c_slave_recv_counter = 0;
				gI2c_slave_send_counter = 0;
				break;

			case E_DD_PMC_I2C_RECV_FROM_MASTER_DATA:
				// received data from mastr
				if( gI2c_slave_recv_counter < 10 ){
					// Replay ACK to master
					ret_act.send_data = D_DD_PMC_I2C_SEND_ACK_MASTER;

					// Get receive data
					*gI2c_slave_recv_address = data;
					gI2c_slave_recv_address++;
					gI2c_slave_recv_counter++;
				}
				else {
					// Replay NOACK to master
					ret_act.action_mode = D_DD_PMC_I2C_SEND_NO_ACK_MASTER;
				}
				break;

			case E_DD_PMC_I2C_RECV_FROM_MASTER_ACK:
				if( gI2c_slave_send_counter < 10 ){
					//Replay ACK to master
					ret_act.action_mode = D_DD_PMC_I2C_SEND_DATA_2_MASTER;

					// Set send data
					ret_act.send_data = *gI2c_slave_send_address;
					gI2c_slave_send_address++;
					gI2c_slave_send_counter++;
				}
				break;

			default:
				break;
		}
	}

	// Set Slave Operation
	VOID slave_set_operation( VOID )
	{
		INT32 ret;
		T_DD_PMC_I2C_CTRL_SLAVE ctrl_slave;
		UCHAR RecvData[10];

		while(1){ // Retry loop as error occur

			ctrl_slave.own_slave_addr_len = E_DD_PMC_I2C_ADDR_LEN_7;
			ctrl_slave.own_slave_addr = 0x45;
			ctrl_slave.global_call_en = FALSE;

			ret = Dd_PMC_I2C_Ctrl_Slave( &ctrl_slave ); // Set Control for Slave Operation
			if( ret == D_DDIM_OK ){

				ret = Dd_PMC_I2C_Start_Slave( i2c_callback_func ); // Start Slave
				if( ret == D_DDIM_OK ){
					break;
				}
			}
		}
	}
	@endcode

@}*//* --- end of dd_pmc_i2c_sequence */

#ifndef _DD_PMC_I2C_H_
#define _DD_PMC_I2C_H_

/** @weakgroup dd_pmc_i2c_definition
@{*/

#include "driver_common.h"

/*----------------------------------------------------------------------*/
/* Definition															*/
/*----------------------------------------------------------------------*/
// Return value of I2C processing result
#define	D_DD_PMC_I2C_INPUT_PARAM_ERROR	(D_DD_PMC_I2C | D_DDIM_INPUT_PARAM_ERROR)	/**< Input parameter error	*/
#define	D_DD_PMC_I2C_STATUS_ABNORMAL	(D_DD_PMC_I2C | D_DDIM_STATUS_ABNORMAL) 	/**< Abnormal status error. */
#define	D_DD_PMC_I2C_TIMEOUT			(D_DD_PMC_I2C | D_DDIM_TIMEOUT) 			/**< Timeout (need to Dd_PMC_I2C_Close())	*/
#define	D_DD_PMC_I2C_BUS_ERROR			(D_DD_PMC_I2C | D_DDIM_BUS_ERROR)			/**< Bus error */
#define	D_DD_PMC_I2C_ARBITRATION_LOST	(D_DD_PMC_I2C | D_DDIM_ARBITRATION_LOST)	/**< Arbitration lost detect */
#define	D_DD_PMC_I2C_COMM_ERROR			(D_DD_PMC_I2C | D_DDIM_COMM_ERROR)			/**< Communication error */
#define	D_DD_PMC_I2C_PEC_ERROR			(D_DD_PMC_I2C | D_DDIM_PARITY_DATA)			/**< Packet Error */

#define D_DD_PMC_I2C_SEND_2_SLAVE		(1)			/**<Send data to Slave		*/
#define D_DD_PMC_I2C_SEND_ACK_SLAVE		(2)			/**<Send ACK to Slave		*/
#define D_DD_PMC_I2C_SEND_NO_ACK_SLAVE	(3)			/**<Send NO ACK to Slave	*/
#define D_DD_PMC_I2C_SEND_DATA_2_MASTER	(4)			/**<Send data to Master		*/
#define D_DD_PMC_I2C_SEND_ACK_MASTER	(5)			/**<Send ACK to Master		*/
#define D_DD_PMC_I2C_SEND_NO_ACK_MASTER (6)			/**<Send NO ACK to Master	*/

/*----------------------------------------------------------------------*/
/* Enumeration															*/
/*----------------------------------------------------------------------*/
/** Recieve action */
typedef enum {
	E_DD_PMC_I2C_RECV_FROM_SLAVE_NO_ACK		= 0,	/**< Receive NO ACK from Slave		*/
	E_DD_PMC_I2C_RECV_FROM_SLAVE_ACK,				/**< Receive ACK from Slave			*/
	E_DD_PMC_I2C_RECV_FROM_SLAVE_ERROR,				/**< Error occured from Slave		*/
	E_DD_PMC_I2C_RECV_FROM_MASTER_NO_ACK,			/**< Receive NO ACK from Master		*/
	E_DD_PMC_I2C_RECV_FROM_MASTER_ACK,				/**< Receive ACK from Master		*/
	E_DD_PMC_I2C_RECV_FROM_MASTER_DATA,				/**< Receive Data from Master		*/
	E_DD_PMC_I2C_RECV_FROM_MASTER_ADDRESS,			/**< Receive Address from Master	*/
	E_DD_PMC_I2C_RECV_FROM_MASTER_ERROR,			/**< Error occured from Master		*/
} E_DD_PMC_I2C_RECV;

/** Communication Mode */
typedef enum {
	E_DD_PMC_I2C_RW_MODE_READ = 0,					/**< Read from slave only	*/
	E_DD_PMC_I2C_RW_MODE_WRITE,						/**< Write to slave only	*/
} E_DD_PMC_I2C_RW_MODE;

/** Communication rate */
typedef enum {
	E_DD_PMC_I2C_BPS_100 = 0,						/**< 100kbps	*/
	E_DD_PMC_I2C_BPS_400							/**< 400kbps	*/
} E_DD_PMC_I2C_BPS;

/** Address length */
typedef enum {
	E_DD_PMC_I2C_ADDR_LEN_7 = 0,					/**< 7 bit address	*/
	E_DD_PMC_I2C_ADDR_LEN_10						/**< 10 bit address	*/
} E_DD_PMC_I2C_ADDR_LEN;

/** Timeout Divider */
typedef enum {
	E_DD_PMC_I2C_TO_DIV_NO_CHECK = 0,				/**< Timer Disabled			*/
	E_DD_PMC_I2C_TO_DIV_4,							/**< Divide by 4			*/
	E_DD_PMC_I2C_TO_DIV_8,							/**< Divide by 8			*/
	E_DD_PMC_I2C_TO_DIV_16,							/**< Divide by 16			*/
} E_DD_PMC_I2C_TO_DIV;


/*----------------------------------------------------------------------*/
/* Structure															*/
/*----------------------------------------------------------------------*/
/** Send Action from slave side */
typedef struct {
	UCHAR action_mode;	/**< Action mode.<br> */
						/**< @ref D_DD_PMC_I2C_SEND_2_SLAVE       : Send to slave<br> */
						/**< @ref D_DD_PMC_I2C_SEND_DATA_2_MASTER : Send data to master<br> */
						/**< @ref D_DD_PMC_I2C_SEND_ACK_MASTER    : Send ACK to master<br> */
						/**< @ref D_DD_PMC_I2C_SEND_NO_ACK_MASTER : Send NO ACK to master<br> */
	UCHAR send_data;	/**< Send data */
}T_DD_PMC_I2C_ACTION;

/**
Type is defined to Callback function pointer.<br>
@param [in] E_DD_PMC_I2C_RECV		Recieved action from master side.
@param [in] UCHAR					Received data from master side.
@retval T_DD_PMC_I2C_ACTION			Send action from slave side.
*/
typedef T_DD_PMC_I2C_ACTION (*VP_PMC_I2C_CALLBACK)(E_DD_PMC_I2C_RECV, UCHAR);

/** Control information for Master */
typedef struct {
	E_DD_PMC_I2C_BPS		bps;					/**< Communication rate	*/
	E_DD_PMC_I2C_ADDR_LEN	dest_slave_addr_len;	/**< Destination slave address length */
	USHORT					dest_slave_addr;		/**< Destination slave address */
} T_DD_PMC_I2C_CTRL_MASTER;

/** Control information for Slave */
typedef struct {
	E_DD_PMC_I2C_ADDR_LEN	own_slave_addr_len;		/**< Own Slave address length */
	USHORT					own_slave_addr;			/**< Own Slave address */
	BOOL 					global_call_en;			/**< Global Call Match Enable */
} T_DD_PMC_I2C_CTRL_SLAVE;

/** Control information for SMBus (for Master and Slave) */
typedef struct {
	BOOL 					alert_resp_en;			/**< Alert Response Match Enable (Slave only) */
	UINT32					pec_num;				/**< PEC(Packet Error Checking) number of bytes */
	E_DD_PMC_I2C_TO_DIV		timeout_div;			/**< Timeout Divider */
	UCHAR					timeout_presc;			/**< Timeout Prescaler ( 0 to 255 ) */
} T_DD_PMC_I2C_CTRL_SMBUS;

/** Start information */
typedef struct {
	E_DD_PMC_I2C_RW_MODE	rw_mode;				/**< Read or Write */
	UINT32					rw_data_len;			/**< Read/Write data length */
	UCHAR* 					rw_data;				/**< Read/Write data */
} T_DD_PMC_I2C_START_INFO;

/*----------------------------------------------------------------------*/
/* Global Data															*/
/*----------------------------------------------------------------------*/
/* Nothing Special */

/*----------------------------------------------------------------------*/
/* Macro																*/
/*----------------------------------------------------------------------*/
/* Nothing Special */

/* @} */	// dd_pmc_i2c_definition group

/** @weakgroup dd_pmc_i2c_api
@{*/
/*----------------------------------------------------------------------*/
/* Function																*/
/*----------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif

/**
Set I2C master contorol information.<br>
@param[in] *ctrl_master		Master control info. @ref T_DD_PMC_I2C_CTRL_MASTER.<br>
@retval D_DDIM_OK						OK
@retval D_DD_PMC_I2C_INPUT_PARAM_ERROR	Input Parameter Error
@remarks Please call either the Dd_PMC_I2C_Ctrl_Master() or Dd_PMC_I2C_Ctrl_Slave().
*/
extern INT32 Dd_PMC_I2C_Ctrl_Master( const T_DD_PMC_I2C_CTRL_MASTER* const ctrl_master );

/**
Get I2C master contorol information.<br>
@param[out] *ctrl_master	Master control info. @ref T_DD_PMC_I2C_CTRL_MASTER.<br>
@retval D_DDIM_OK						OK
@retval D_DD_PMC_I2C_INPUT_PARAM_ERROR	Input Parameter Error
*/
extern INT32 Dd_PMC_I2C_Get_Ctrl_Master( T_DD_PMC_I2C_CTRL_MASTER* const ctrl_master );

/**
Set I2C slave contorol information.<br>
@param[in] *ctrl_slave		Slave control info. @ref T_DD_PMC_I2C_CTRL_SLAVE.<br>
@retval D_DDIM_OK						OK
@retval D_DD_PMC_I2C_INPUT_PARAM_ERROR	Input Parameter Error
@remarks Please call either the Dd_PMC_I2C_Ctrl_Master() or Dd_PMC_I2C_Ctrl_Slave().
*/
extern INT32 Dd_PMC_I2C_Ctrl_Slave( const T_DD_PMC_I2C_CTRL_SLAVE* const ctrl_slave );

/**
Get I2C slave contorol information.<br>
@param[out] *ctrl_slave		Slave control info. @ref T_DD_PMC_I2C_CTRL_SLAVE.<br>
@retval D_DDIM_OK						OK
@retval D_DD_PMC_I2C_INPUT_PARAM_ERROR	Input Parameter Error
*/
extern INT32 Dd_PMC_I2C_Get_Ctrl_Slave( T_DD_PMC_I2C_CTRL_SLAVE* const ctrl_slave );

/**
Set SMBus slave contorol information.<br>
@param[in] *ctrl_smbus		SMBus Control info. @ref T_DD_PMC_I2C_CTRL_SMBUS.<br>
@retval D_DDIM_OK						OK
@retval D_DD_PMC_I2C_INPUT_PARAM_ERROR	Input Parameter Error
@retval D_DD_PMC_I2C_STATUS_ABNORMAL	Abnormal Status 
@remarks Please call this API as necessary after the Dd_PMC_I2C_Ctrl_Master() or Dd_PMC_I2C_Ctrl_Slave().
@remarks If you want to enable the PEC, please set the transmit and receive data byte number(T_DD_PMC_I2C_START_INFO.rw_data_len) + 1.
*/
extern INT32 Dd_PMC_I2C_Ctrl_SMBus( const T_DD_PMC_I2C_CTRL_SMBUS* const ctrl_smbus );

/**
Get SMBus slave contorol information.<br>
@param[out] *ctrl_smbus		SMBus Control info. @ref T_DD_PMC_I2C_CTRL_SMBUS.<br>
@retval D_DDIM_OK						OK
@retval D_DD_PMC_I2C_INPUT_PARAM_ERROR	Input Parameter Error
@retval D_DD_PMC_I2C_STATUS_ABNORMAL	Abnormal Status 
*/
extern INT32 Dd_PMC_I2C_Get_Ctrl_SMBus( T_DD_PMC_I2C_CTRL_SMBUS* const ctrl_smbus );

/**
Send start condition.
@param[in] start_info	Start information
@param[in] callback		Callback function pointer. See @ref VP_PMC_I2C_CALLBACK.
@retval D_DDIM_OK						OK
@retval D_DD_PMC_I2C_INPUT_PARAM_ERROR	Input Parameter Error
@retval D_DD_PMC_I2C_ERROR				System Error
@retval D_DD_PMC_I2C_BUS_ERROR			Bus Error
@retval D_DD_PMC_I2C_ARBITRATION_LOST	Arbitration lost detect
@retval D_DD_PMC_I2C_COMM_ERROR			Communication Error
@retval D_DD_PMC_I2C_TIMEOUT			Process Timeout
@retval D_DD_PMC_I2C_STATUS_ABNORMAL	Abnormal Status
*/
extern INT32 Dd_PMC_I2C_Start_Master( const T_DD_PMC_I2C_START_INFO* const start_info, VP_PMC_I2C_CALLBACK callback );

/**
Send stop condition.
@retval D_DDIM_OK						OK
@retval D_DD_PMC_I2C_STATUS_ABNORMAL	Abnormal Status
*/
extern INT32 Dd_PMC_I2C_Stop_Master( VOID );

/**
Master force stop.
*/
extern VOID Dd_PMC_I2C_Force_Stop_Master( VOID );

/**
Start the communication waiting from the master.
@param[in] callback		Callback function pointer. See @ref VP_PMC_I2C_CALLBACK.
@retval D_DDIM_OK						OK
@retval D_DD_PMC_I2C_INPUT_PARAM_ERROR	Input Parameter Error
@retval D_DD_PMC_I2C_STATUS_ABNORMAL	Abnormal Status
*/
extern INT32 Dd_PMC_I2C_Start_Slave( VP_PMC_I2C_CALLBACK callback );

/**
Stop thje communication waiting from the master.
*/
extern VOID Dd_PMC_I2C_Stop_Slave( VOID );

/**
To terminate the I2C.
*/
extern VOID Dd_PMC_I2C_Terminate( VOID );

/**
Set Toggle SCL.<br>
When SDA is low, setting 1 to this API toggles SCL for one cycle.<br>
Setting 1 to this API while SDA is high is ignored.<br>
*/
extern VOID Dd_PMC_I2C_Set_Toggle_SCL( VOID );

/**
Get Test SDA.
@param[out] sda		Test SDA value ( 0:Low, 1:High )
@retval D_DDIM_OK						OK
@retval D_DD_PMC_I2C_INPUT_PARAM_ERROR	Input Parameter Error
*/
extern INT32 Dd_PMC_I2C_Get_Test_SDA( UCHAR* sda );

/**
Get Error Cause.
@retval D_DDIM_OK						: OK
@retval	D_DD_PMC_I2C_TIMEOUT			: Timeout (need to Dd_I2C_Close())
@retval	D_DD_PMC_I2C_BUS_ERROR			: Bus error
@retval	D_DD_PMC_I2C_ARBITRATION_LOST	: Arbitration lost detect
@retval	D_DD_PMC_I2C_COMM_ERROR			: Communication error
@retval	D_DD_PMC_I2C_PEC_ERROR			: Packet Error
*/
extern UINT32 Dd_PMC_I2C_Get_Error_Cause( VOID );

/**
Interrupt handler.<br>
The interruption flag is cleared, and the CallBack function is called.<br>
(Only an interruption clear flag of CallBack when it is unregistered.)
*/
extern VOID Dd_PMC_I2C_Int_Handler( VOID );


#ifdef CO_DDIM_UTILITY_USE
//---------------------- utility section -------------------------------
/**
Set SCL frequency utility function.<br>
@param [in] scl	SCL frequency (range of 4..127)
@retval D_DDIM_OK						OK
@retval D_DD_PMC_I2C_INPUT_PARAM_ERROR	Input Parameter Error
@remarks Selecting a value of less than 4 will automatically default by adding an offset of 4.
*/
extern INT32 Dd_PMC_I2C_Set_SCL( UCHAR scl );

/**
Get SCL frequency utility function.<br>
@param [out] scl	SCL frequency
@retval D_DDIM_OK						OK
@retval D_DD_PMC_I2C_INPUT_PARAM_ERROR	Input Parameter Error
*/
extern INT32 Dd_PMC_I2C_Get_SCL( UCHAR* scl );

#endif	// CO_DDIM_UTILITY_USE

// aDvfs =============================---------------------------
typedef struct {
	UCHAR AVS;
	UCHAR DVFS;
}
T_DD_PMC_ADVFS_DATA;

extern int Dd_PMC_ADVFS_Set_EN(const UCHAR en);
extern int Dd_PMC_ADVFS_Set_Avs(const UCHAR avs);
extern int Dd_PMC_ADVFS_Set_Dvfs(const UCHAR dvfs);

extern int Dd_PMC_ADVFS_Get_EN(UCHAR *const en);
extern int Dd_PMC_ADVFS_Get_Advfs(T_DD_PMC_ADVFS_DATA *const advfs);

#ifdef __cplusplus
}
#endif

/* @} */	// dd_pmc_i2c_api group

#endif	// _DD_PMC_I2C_H_

